﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Backup;
using System.Net.Mail;
using System.IO;
using System.Diagnostics;


namespace SPBackup
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                DayOfWeek strDay = DateTime.Now.DayOfWeek;
                //Each backup will be place in a folder with the day of the week as its name.  This folder will be deleted each week before a new backup is created.
                string strPathInfo = SPBackup.Default.BackupPath + "\\" + strDay;

                if (Directory.Exists(strPathInfo))
                {
                    Directory.Delete(strPathInfo, true);
                    Directory.CreateDirectory(strPathInfo);
                }
                else
                {
                    Directory.CreateDirectory(strPathInfo);
                }

                //The path where you are backing up too
                String backupLocation = strPathInfo;

                //Backup setting similar to stsadm -o backup for catastrophic backup
                SPBackupSettings settings = SPBackupRestoreSettings.GetBackupSettings(backupLocation, "Full");

                //Leave this setting blank to backup whole farm.  Enter Web App to only backup certian web applications
                settings.IndividualItem = SPBackup.Default.WebAppToBackup;
                settings.IsVerbose = true;
                settings.UpdateProgress = 10;
                byte backupThreads = Convert.ToByte(SPBackup.Default.NumberofThreads);
                settings.BackupThreads = backupThreads;
                Guid backup = SPBackupRestoreConsole.CreateBackupRestore(settings);
                SPBackupRestoreObject node = EnsureUniqueValidComponentName(settings, ref backup);

                if (node != null)
                {

                    //Disk space needed for backup
                    ulong intDiskSizeRequired = SPBackupRestoreConsole.DiskSizeRequired(backup, node);
                    intDiskSizeRequired = (intDiskSizeRequired / 1024) / 1024;
                    string strDiskSpaceRequired = intDiskSizeRequired.ToString();

                    //Disk space Available for Backup
                    UInt64 diskFreeSize = 0;
                    UInt64 diskSize = 0;
                    SPBackupRestoreConsole.DiskSize(backupLocation, out diskFreeSize, out diskSize);
                    ulong intDiskAvailable = diskFreeSize;
                    intDiskAvailable = ((intDiskAvailable / 1024) / 1024) / 1024;
                    string strNode = node.ToString();


                    Boolean targetHasEnoughSpace = false;
                    if (node != null)
                    {
                        targetHasEnoughSpace = EnsureEnoughDiskSpace(backupLocation, backup, node);
                    }

                    if (targetHasEnoughSpace)
                    {
                        if (SPBackupRestoreConsole.SetActive(backup))
                        {
                            if (!SPBackupRestoreConsole.Run(backup, node))
                            {
                                //Report Error
                                string Error = SPBackupRestoreConsole.Get(backup).FailureMessage;
                                Console.WriteLine(Error);
                                SendErrorEmail(Error);
                            }

                        }
                        else
                        {
                            //Report what is happening
                            string Error = "Another Backup or Restore Operation is underway";
                            Console.WriteLine(Error);
                            SendErrorEmail(Error);
                        }
                        DateTime strStartTime = SPBackupRestoreConsole.Get(backup).StartTime;
                        strStartTime = strStartTime.ToLocalTime();
                        DateTime strFinishTime = SPBackupRestoreConsole.Get(backup).FinishTime;
                        strFinishTime = strFinishTime.ToLocalTime();
                        TimeSpan strTotal = strFinishTime - strStartTime;
                        string strErrorCount = SPBackupRestoreConsole.Get(backup).ErrorCount.ToString();
                        string strWarningCount = SPBackupRestoreConsole.Get(backup).WarningCount.ToString();
                        SendEmail(strDiskSpaceRequired, strTotal, intDiskAvailable, strNode, strErrorCount, strWarningCount, strStartTime, strFinishTime,strPathInfo);
                        SPBackupRestoreConsole.Remove(backup);

                    }
                }
            }
            catch (Exception ex)
            {
                string strBody = ex.Message;
                MailMessage message = new MailMessage(SPBackup.Default.strFromAddress, SPBackup.Default.strToErrorAddress, SPBackup.Default.strFailureSubject, strBody);
                SmtpClient emailClient = new SmtpClient(SPBackup.Default.strSMTPServer);
                emailClient.Send(message);
            }

        }
        private static SPBackupRestoreObject EnsureUniqueValidComponentName(SPBackupRestoreSettings settings, ref Guid operationGUID)
        {

            SPBackupRestoreObjectCollection list = SPBackupRestoreConsole.FindItems(operationGUID, settings.IndividualItem);

            SPBackupRestoreObject component = null;


            if (list.Count <= 0)
            {
                string Error = "There is no component with that name. Run again with a new name.";
                Console.WriteLine(Error);
                SendErrorEmail(Error);

            }

            else if (list.Count > 1)  // The component name specified is ambiguous. Prompt user to be more specific.
            {

                string Error = "More than one component matches the name you entered. \r\n";
                Console.WriteLine(Error);
                Error = Error + "Run again with one of the following: \r\n";
                                
                for (int i = 0; i < list.Count; i++)
                {

                    Error = Error + list[i].ToString();
                    Console.WriteLine(Error);

                }
                SendErrorEmail (Error);

            }

            else
            {

                component = list[0];

            }


            return component;


        }// end EnsureUniqueValidComponentName

        private static Boolean EnsureEnoughDiskSpace(String location, Guid backup, SPBackupRestoreObject node)
        {
            UInt64 backupSize = SPBackupRestoreConsole.DiskSizeRequired(backup, node);
            UInt64 diskFreeSize = 0;
            UInt64 diskSize = 0;
            Boolean hasEnoughSpace = true;

            try
            {
                SPBackupRestoreConsole.DiskSize(location, out diskFreeSize, out diskSize);
            }
            catch
            {
                diskFreeSize = diskSize = UInt64.MaxValue;
            }

            if (backupSize > diskFreeSize)
            {
                string Error = (backupSize + " bytes of space is needed but the disk hosting " + location + " has only " + diskFreeSize);
                Console.WriteLine(Error);
                SendErrorEmail(Error);
                hasEnoughSpace = false;
            }
            else if (backupSize == UInt64.MaxValue || diskFreeSize == 0)
            {
                Console.WriteLine("Cannot determine if that location has enough disk space");
                string Error = "Cannot determine if that location has enough disk space";
                Console.WriteLine("Try something else");
                SendErrorEmail(Error);
                hasEnoughSpace = false;
            }
            return hasEnoughSpace; 
            
        }

        static void SendEmail(string strDispSpaceRequired, TimeSpan strTotalTime, ulong diskFreeSize, string strNode, string strErrorCount, string strWarningCount, DateTime strStartTime, DateTime strFinishTime, string strPathInfo)
        {
            string strBody = "Disk Space Required in MB: " + strDispSpaceRequired + "\r\n";
            strBody = strBody + "Total Run Time: " + strTotalTime.ToString() + "\r\n";
            strBody = strBody + "Available Disk Space in GB: " + diskFreeSize + "\r\n";
            strBody = strBody + "Node being backed up: " + strNode + "\r\n";
            strBody = strBody + Environment.NewLine;
            strBody = strBody + "Error Count: " + strErrorCount + "\r\n";
            strBody = strBody + "Warning Count: " + strWarningCount + "\r\n";
            strBody = strBody + "Backup location: " + strPathInfo + "\n";
            strBody = strBody + Environment.NewLine;
            strBody = strBody + "Start Time: " + strStartTime + "\r\n";
            strBody = strBody + "Finish Time: " + strFinishTime + "\r\n";
            strBody = strBody + "Server backed up: " + System.Environment.MachineName + "\r\n";
            strBody = strBody + "User Running Backup: " + System.Environment.UserName + "\r\n";
            MailMessage message = new MailMessage(SPBackup.Default.strFromAddress, SPBackup.Default.strToAddress, SPBackup.Default.strSubject, strBody);
            SmtpClient emailClient = new SmtpClient(SPBackup.Default.strSMTPServer);
            emailClient.Send(message);
            EventLog.WriteEntry("SharePoint Backup Suceeded", strBody, EventLogEntryType.Information);
        }
        static void SendErrorEmail(string Error)
        {
            string strBody = Error + "\r\n";
            MailMessage message = new MailMessage(SPBackup.Default.strFromAddress, SPBackup.Default.strToErrorAddress, SPBackup.Default.strFailureSubject, strBody);
            message.Priority = MailPriority.High;
            SmtpClient emailClient = new SmtpClient(SPBackup.Default.strSMTPServer);
            emailClient.Send(message);
            EventLog.WriteEntry("SharePoint Backup Failed", strBody, EventLogEntryType.Error);
        }
    }

}
